with ada.text_io;
with ada.integer_text_io;
with v_string;
use v_string;

package body currency is

    package i_io renames ada.integer_text_io;
    package t_io renames ada.text_io;

    function add ( in_amount1 : dollar; in_amount2 : dollar ) return dollar is
	sum : dollar;
	amount1, amount2 : dollar;
    begin
	amount1 := in_amount1;
	amount2 := in_amount2;
	if amount1.is_positive = false and amount2.is_positive = false then
	    sum.is_positive := false;
	    amount1.is_positive := true;
	    amount2.is_positive := true;
	elsif amount1.is_positive = false then
	    amount1.is_positive := true;
	    return subtract(amount2, amount1);
	elsif amount2.is_positive = false then
	    amount2.is_positive := true;
	    return subtract(amount1, amount2);
	else
	    sum.is_positive := true;
	end if;

	sum.whole := amount1.whole + amount2.whole;

	if (amount1.cents + amount2.cents) > 100 then
	    sum.cents := amount1.cents + amount2.cents - 100;
	    sum.whole := 1 + sum.whole;
	else
	    sum.cents := amount1.cents + amount2.cents;
	end if;

	return sum;
    end add;

    function subtract ( in_base : dollar; in_subtractor : dollar ) return dollar is
	remainder, tmp : dollar;
	base, subtractor : dollar;
    begin
	base := in_base;
	subtractor := in_subtractor;
	if base.is_positive = false and subtractor.is_positive = false then
	    subtractor.is_positive := true;
	    return add(base, subtractor);
	elsif base.is_positive = false then
	    base.is_positive := true;
	    return -add(base, subtractor);
	elsif subtractor.is_positive = false then
	    subtractor.is_positive := true;
	    return add(base, subtractor);
	end if;
	if base < subtractor then
	    tmp := base;
	    base := subtractor;
	    subtractor := tmp;
	    remainder.is_positive := false;
	else
	    remainder.is_positive := true;
	end if;

	remainder.whole := base.whole - subtractor.whole;
	if base.cents < subtractor.cents then
	    base.cents := base.cents + 100;
	    remainder.whole := remainder.whole - 1;
	end if;
	remainder.cents := base.cents - subtractor.cents;
	return remainder;
    end subtract;

    function multiply (base : dollar; multiplier : float ) return dollar is
	product : float;
    begin
	product := dollar_to_float(base) * multiplier;
	return float_to_dollar(product);
    end multiply;

    function float_to_dollar ( float_amount : float ) return dollar is
	newDollar : dollar;
	whole : float;
    begin
	whole := float'truncation(float_amount);
	if whole < 0.0 then
	    newDollar.is_positive := false;
	    whole := -whole;
	else
	    newDollar.is_positive := true;
	end if;
	newDollar.whole := integer(whole);
	newDollar.cents := Integer((abs float_amount - float(newDollar.whole)) * 100.00);
	return newDollar;
    end float_to_dollar;

    function dollar_to_float ( dollar_amount : dollar ) return float is
    begin
	return float(dollar_amount.whole + dollar_amount.cents);
    end dollar_to_float;

    function vstring_to_dollar ( vstr : vstring ) return dollar is
	newDollar : dollar;
	index, start, pos : natural;
    begin
	start := 1;
	if vstr.buf(start) = '-' then
	    newDollar.is_positive := false;
	    start := start + 1;
	else
	    newDollar.is_positive := true;
	end if;
	index := start;
	pos := 0;
	newDollar.whole := 0;
	loop
	    newDollar.whole := newDollar.whole * (10**pos) + (Character'pos(vstr.buf(index)) - Character'pos('0'));
	    pos := pos + 1;
	    index := index + 1;
	    exit when vstr.buf(index) = '.' or index > vstr.len;
	end loop;
	if index <= vstr.len then
	    index := index + 1;
	    newDollar.cents := 10 * (Character'pos(vstr.buf(index)) - Character'pos('0'));
	    index := index + 1;
	    if index < vstr.len then
		newDollar.cents := newDollar.cents + (Character'pos(vstr.buf(index)) - Character'pos('0'));
		if (Character'pos(vstr.buf(index+1)) - Character'pos('0')) > 4 then
		    newDollar.cents := newDollar.cents + 1;
		end if;
	    end if;
	else
	    newDollar.cents := 0;
	end if;
	return newDollar;
    end vstring_to_dollar;


	


    function "-" (in_right : dollar ) return dollar is
	right : dollar;
    begin
	right := in_right;
	if right.is_positive = true then
	    right.is_positive := false;
	else
	    right.is_positive := true;
	end if;
	return right;
    end "-";

    function "<" (left : dollar; right : dollar ) return boolean is
    begin
	if left.whole = right.whole then
	    if left.cents < right.cents then
		return true;
	    else 
		return false;
	    end if;
	elsif left.whole < right.whole then
	    return true;
	else
	    return false;
	end if;
    end "<";

    function ">" (left : dollar; right : dollar ) return boolean is
    begin
	if left.whole = right.whole then
	    if left.cents > right.cents then
		return true;
	    else
		return false;
	    end if;
	elsif left.whole > right.whole then
	    return true;
	else
	    return false;
	end if;
    end ">";

    procedure print ( in_dollar : dollar ) is
    begin
	if in_dollar.is_positive = false then
	    t_io.put("-");
	end if;
	t_io.put("$");
	i_io.put(item => in_dollar.whole, width => 0);
	t_io.put(".");
	if in_dollar.cents < 10 then
	    t_io.put("0");
	end if;
	i_io.put(item => in_dollar.cents, width => 0);
    end print;
	
end currency;
